﻿using log4net;
using System;
using System.Reflection;
using Velocity4Net.Errors;
using Velocity4Net.Util;
using Velocity4Net.Util.Introspection;

namespace Velocity4Net.Runtime.Parser.Node
{

    /*
     * Licensed to the Apache Software Foundation (ASF) under one
     * or more contributor license agreements.  See the NOTICE file
     * distributed with this work for additional information
     * regarding copyright ownership.  The ASF licenses this file
     * to you under the Apache License, Version 2.0 (the
     * "License"); you may not use this file except in compliance
     * with the License.  You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing,
     * software distributed under the License is distributed on an
     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     * KIND, either express or implied.  See the License for the
     * specific language governing permissions and limitations
     * under the License.
     */









    /**
     * Returns the value of a public field when executed.
     */
    public class PublicFieldExecutor : AbstractExecutor
    {
        private readonly Introspector introspector;

        /**
         * Field to be accessed
         */
        private FieldInfo field = null;

        /**
         * @param log
         * @param introspector
         * @param clazz
         * @param property
         * @since 1.5
         */
        public PublicFieldExecutor(ILog log, Introspector introspector,
                Type clazz, String property)
        {
            this.log = log;
            this.introspector = introspector;

            // Don't allow passing in the empty string or null because
            // it will either fail with a StringIndexOutOfBounds error
            // or the introspector will get confused.
            if (String.IsNullOrEmpty(property))
            {
                discover(clazz, property);
            }
        }

        public bool isAlive()
        {
            return getField() != null;
        }

        /**
         * @return The current field.
         */
        public FieldInfo getField()
        {
            return field;
        }

        /**
         * @param field
         */
        protected void setField(FieldInfo field)
        {
            this.field = field;
        }

        /**
         * @return The current introspector.
         * @since 1.5
         */
        protected Introspector getIntrospector()
        {
            return this.introspector;
        }

        /**
         * @param clazz
         * @param property
         */
        protected void discover(Type clazz, String property)
        {
            try
            {
                setField(introspector.getField(clazz, property));
            }
            /**
             * pass through application level runtime exceptions
             */
            catch (SystemException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String msg = "Exception while looking for public field '" + property;
                log.Error(msg, e);
                throw new VelocityException(msg, e);
            }
        }

        /**
         * @see org.apache.velocity.runtime.parser.node.AbstractExecutor#execute(java.lang.Object)
         */
        public override Object execute(Object o)
        {
            return isAlive() ? getField().get(o) : null;
        }
    }
}